package view;

import java.awt.Color;
import java.awt.Component;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JToolBar;

import controller.ConnectionTester;
import model.environmentConfig.CommunicationChannel;
import model.environmentConfig.EnvironmentConfiguration;
import model.environmentConfig.Node;
import model.environmentConfig.NodeState;


public class Toolbar extends JToolBar implements ActionListener{
	private JLabel title;
	private ButtonGroup group = new ButtonGroup();
	private JRadioButton nothing = new JRadioButton("Run Nothing");
	private JRadioButton simulation = new JRadioButton("Run Simulation");
	private JRadioButton software = new JRadioButton("Run Software");
	public Toolbar(){
		super(Toolbar.VERTICAL);
		//this.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3));
		title = new JLabel("Toolbar");
		this.add(title);
	}
	
	public JButton makeButton(String imgName, String altText){
		JButton button = null;
		button = new JButton();
		
		Insets margins = new Insets(0,0,0,0);
		button.setBackground(Color.WHITE);
		button.setMargin(margins);
		String imgLocation = "../images/"
                + imgName
                + ".gif";
		URL imageURL = EnvironmentConfigDesignerPanel.class.getResource(imgLocation);
		
		if(imageURL != null){
			button.setIcon(new ImageIcon(imageURL, altText));
			setAction(button, altText, new ImageIcon(imageURL, altText));
			button.setText("");
		}
		else {
			button.setText(altText);
			System.err.println("Resource not found: " + imgLocation );
		}
		button.setToolTipText(altText);
		//button.setVerticalTextPosition(BOTTOM);
		return button;
	}
	
	public void setupNodeGroupButtons(){
		group.add(nothing);
		group.add(simulation);
		group.add(software);
		nothing.addActionListener(this);
		simulation.addActionListener(this);
		software.addActionListener(this);
		this.add(nothing);
		this.add(simulation);
		this.add(software);
		
	}
	
	public void actionPerformed(ActionEvent e) {
	    if(e.getSource() == nothing){
	    	((Node)ConnectionTester.getEnvironmentConfig().getSelectedObj())
	    	.setNodeState(NodeState.RUNNING_NOTHING);
	    } else if(e.getSource() == simulation){
	    	((Node)ConnectionTester.getEnvironmentConfig().getSelectedObj())
	    	.setNodeState(NodeState.RUNNING_SIMULATION);
	    } else if(e.getSource() == software){
	    	((Node)ConnectionTester.getEnvironmentConfig().getSelectedObj())
	    	.setNodeState(NodeState.RUNNING_SOFTWARE);
	    }
	}
	
	public void setAction(AbstractButton button, String text, ImageIcon icon){
		if(text.equals("New")){
			button.setAction(new NewEnvConfigAction(text, icon));
		}
		else if(text.equals("Open")){
			button.setAction(new OpenEnvConfigAction(text, icon));
		}
		else if(text.equals("Save")){
			button.setAction(new SaveEnvConfigAction(text, icon));
		}
		else if(text.equals("Copy")){
			button.setAction(new CopyEnvConfigAction(text, icon));
		}
		else if(text.equals("Delete")){
			button.setAction(new DeleteEnvConfigAction(text, icon));
		}
		else if(text.equals("Report")){
			button.setAction(new GenerateEnvConfigDocAction(text, icon));
		}
		else if(text.equals("Submit")){
			button.setAction(new SubmitEnvConfigAction(text, icon));
		}
		else if(text.equals("Approve")){
			button.setAction(new ApproveEnvConfigAction(text, icon));
		}
		else if(text.equals("Reject")){
			button.setAction(new RejectEnvConfigAction(text, icon));
		}
		else if(text.equals("Add Node")){
			button.setAction(new NewNodeAction(text, icon));
		}
		else if(text.equals("Add Channel")){
			button.setAction(new NewChannelAction(text, icon));
		}
		else if(text.equals("Simulation Mode")){
			button.setAction(new SimModeAction(text, icon));
		}
		else if(text.equals("Security Mode")){
			button.setAction(new SecurityModeAction(text, icon));
		}
		else if(text.equals("Edit Configuration Mode")){
			button.setAction(new EditModeAction(text, icon));
		}
		else if(text.equals("Run Simulation")){
			button.setAction(new RunSimulationAction(text, icon));
		}
		else if(text.equals("Stop Simulation")){
			button.setAction(new StopSimulationAction(text, icon));
		}
		else if(text.equals("Delete Node")){
			button.setAction(new DeleteNodeAction(text, icon));
		}
		else if(text.equals("Delete Channel")){
			button.setAction(new DeleteChannelAction(text, icon));
		}
		else if(text.equals("Click if current node is this machine")){
			button.setAction(new SetSimNodeAction(text, icon));
		}
	}
	
	//ACTIONS
		private class SetSimNodeAction extends AbstractAction{
			public SetSimNodeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				EnvironmentConfiguration envConf=ConnectionTester.getEnvironmentConfig();
				if(envConf==null || !(envConf.getSelectedObj() instanceof Node)){
					return;
				}
				
				envConf.setSimulatingNode((Node)envConf.getSelectedObj());
				MainFrame.refresh();
			}
		}
	
		private class NewEnvConfigAction extends AbstractAction{
			public NewEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				int result = JOptionPane.showConfirmDialog(null, 
						"Any unsaved changes will be lost",
						"Confirm", JOptionPane.OK_CANCEL_OPTION);

			      if (result == JOptionPane.OK_OPTION) {
			    	  ConnectionTester.newEnvironment();
			      }
				System.out.println("Creating New EnvironmentConfig in Canvas");
			}
		}
		
		private class OpenEnvConfigAction extends AbstractAction{
			public OpenEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				//create new
				List<String> files = ConnectionTester.getConfigList();
				Object[] folders = {"new", "rejected", "submitted", "approved"};
				if(ConnectionTester.getMode() == Mode.DESIGNER) {
					String folder = (String)JOptionPane.showInputDialog(
		                    null,
		                    "Select Folder",
		                    "Load from which folder?",
		                    JOptionPane.PLAIN_MESSAGE,
		                    null,
		                    folders,
		                    files.get(0).toString());
					if(folder == null){
						return;
					} else if(folder.equals("submitted")){
						files = ConnectionTester.getSubmittedList();
					} else if(folder.equals("rejected")){
						files = ConnectionTester.getRejectedList();
					} else if(folder.equals("approved")){
						files = ConnectionTester.getApprovedList();
					} else {
						files = ConnectionTester.getConfigList();
					}
				} else if(ConnectionTester.getMode() == Mode.SECURITY) {
					files = ConnectionTester.getSubmittedList();
				} else {
					files = ConnectionTester.getApprovedList();
				}
				for(String file : files){
					int index = files.indexOf(file);
					file = file.split("\\.")[0];
					files.set(index, file);
				}
				if(files.isEmpty()){
					JOptionPane.showMessageDialog(null, "Folder is Empty");
					return;
				}
				Object[] possibilities = files.toArray();
				String s = (String)JOptionPane.showInputDialog(
				                    null,
				                    "Select xml",
				                    "Open Configuration",
				                    JOptionPane.PLAIN_MESSAGE,
				                    null,
				                    possibilities,
				                    files.get(0).toString());
				if(s != null){
					if(ConnectionTester.getMode() == Mode.DESIGNER) {
						ConnectionTester.loadEnvironment("./xmls/" + s +".xml");
					} else if(ConnectionTester.getMode() == Mode.SECURITY) {
						ConnectionTester.loadEnvironment("./submitted/" + s + ".xml");
					} else {
						ConnectionTester.loadEnvironment("./approved/" + s + ".xml");
					}
					
				}
				System.out.println("Opening New EnvironmentConfig in Canvas");
				((MainPanel)getParentContainer()).refreshAttributesPanel();
				MainFrame.refresh();
			}
		}
		
		public Component getParentContainer(){
			return this.getParent();
		}
		
		private class SimModeAction extends AbstractAction{
			public SimModeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				//create new
				System.out.println("Switching to Simulation Mode");
				ConnectionTester.setSimulatorMode();
				MainFrame.LaunchSimulationGUI();
			}
		}
		
		
		private class SaveEnvConfigAction extends AbstractAction{
			public SaveEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				
				
				List<String> files = new ArrayList<String>();
				String xmlFile = ConnectionTester.getConfigFileName();
				String s = null;
				if(xmlFile != null){
					xmlFile = xmlFile.split("\\.")[0];
					files.add(xmlFile);
					files.add("Save As");
					Object[] possibilities = files.toArray();
					s = (String)JOptionPane.showInputDialog(
		                    null,
		                    "Select xml",
		                    "Open Configuration",
		                    JOptionPane.PLAIN_MESSAGE,
		                    null,
		                    possibilities,
		                    files.get(0).toString());
				}
				if(s != null && !s.equals("Save As")){
					ConnectionTester.saveEnvironment("./xmls/" + s +".xml");
				} else if (s != null || xmlFile == null){
					String newname = null;
					while(newname == null){
						newname = (String)JOptionPane.showInputDialog(null,
								"Enter a new file name",
								newname);
						if(newname.equals("")){
							newname = null;
						}
					}
					if(newname != null){
						ConnectionTester.saveEnvironment("./xmls/" + newname + ".xml");
						ConnectionTester.getEnvironmentConfig().setFileName(newname + ".xml");
					}
				}
				System.out.println("Saving EnvironmentConfig in Canvas");
			}
		}
		
		private class CopyEnvConfigAction extends AbstractAction{
			public CopyEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				List<String> files = ConnectionTester.getConfigList();
				for(String file : files){
					int index = files.indexOf(file);
					file = file.split("\\.")[0];
					files.set(index, file);
				}
				Object[] possibilities = files.toArray();
				String newname = "";
				String s = (String)JOptionPane.showInputDialog(
			                    null,
			                    "Select xml",
			                    "Copy Configuration",
			                    JOptionPane.PLAIN_MESSAGE,
			                    null,
			                    possibilities,
			                    files.get(0).toString());
				if(s != null){
					newname = s;
					while((newname.equals(s) || newname.equals("")) && newname != null){
						newname = (String)JOptionPane.showInputDialog(null,
								"Enter a new file name",
								newname);
					}
					if(newname != null){
						ConnectionTester.copyEnvironment("./xmls/" + s + ".xml", newname);
					}
				} 
				System.out.println("Copying EnvironmentConfig");
			}
		}
		
		private class DeleteEnvConfigAction extends AbstractAction{
			public DeleteEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				List<String> files = ConnectionTester.getConfigList();
				Object[] folders = {"new", "rejected"};
				String folder = null;
				if(ConnectionTester.getMode() == Mode.DESIGNER) {
					folder = (String)JOptionPane.showInputDialog(
		                    null,
		                    "Select Folder",
		                    "Delete from which folder?",
		                    JOptionPane.PLAIN_MESSAGE,
		                    null,
		                    folders,
		                    files.get(0).toString());
					if(folder == null){
						return;
					} else if(folder.equals("rejected")){
						files = ConnectionTester.getRejectedList();
					} else {
						files = ConnectionTester.getConfigList();
					}
				}
				for(String file : files){
					int index = files.indexOf(file);
					file = file.split("\\.")[0];
					files.set(index, file);
				}
				if(files.isEmpty()){
					JOptionPane.showMessageDialog(null, "Folder is Empty");
					return;
				}
				Object[] possibilities = files.toArray();
				String s = (String)JOptionPane.showInputDialog(
				                    null,
				                    "Select xml",
				                    "Delete Configuration",
				                    JOptionPane.PLAIN_MESSAGE,
				                    null,
				                    possibilities,
				                    files.get(0).toString());
				if(s != null){
					if(folder.equals("rejected")){
						ConnectionTester.deleteEnvironment("./rejected/" + s + ".xml");

					} else {
						ConnectionTester.deleteEnvironment("./xmls/" + s + ".xml");
					}
				} 
				System.out.println("Deleting EnvironmentConfig");
			}
		}
		
		private class GenerateEnvConfigDocAction extends AbstractAction{
			public GenerateEnvConfigDocAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				List<String> files = ConnectionTester.getConfigList();
				for(String file : files){
					int index = files.indexOf(file);
					file = file.split("\\.")[0];
					files.set(index, file);
				}
				Object[] possibilities = files.toArray();
				String newname = "";
				String s = (String)JOptionPane.showInputDialog(
			                    null,
			                    "Select xml",
			                    "Generate Report",
			                    JOptionPane.PLAIN_MESSAGE,
			                    null,
			                    possibilities,
			                    files.get(0).toString());
				if(s != null){
					newname = s;
					while((newname.equals(s) || newname.equals("")) && newname != null){
						newname = (String)JOptionPane.showInputDialog(null,
								"Enter a report name",
								newname);
					}
					if(newname != null){
						ConnectionTester.generateEnvDoc("./xmls/" + s + ".xml", newname);
					}
				} 
				System.out.println("Generating Report");
			}
		}
		
		private class SubmitEnvConfigAction extends AbstractAction
		{
			public SubmitEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}
			

			@Override
			public void actionPerformed(ActionEvent arg0) {
				
				String s = ConnectionTester.getConfigFileName();
				if(s != null)
				{
					ConnectionTester.saveEnvironment("./submitted/" + s +".xml");
					ConnectionTester.deleteEnvironment("./xmls/" + s +".xml");
				} else {
					JOptionPane.showMessageDialog(null, "No file loaded");
					return;
				}
			}
		}
		
		private class ApproveEnvConfigAction extends AbstractAction
		{
			public ApproveEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}

			@Override
			public void actionPerformed(ActionEvent arg0) {
				String s = ConnectionTester.getConfigFileName();
				if(s != null){
					DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
					Date date = new Date();
					System.out.println(dateFormat.format(date));
					ConnectionTester.deleteEnvironment("./submitted/" + s + ".xml");
					s = s + dateFormat.format(date); 
					s = s.replace("/", "");
					s = s.replace(":", "");
					ConnectionTester.saveEnvironment("./approved/" + s +".xml");
				} else {
					JOptionPane.showMessageDialog(null, "No file loaded");
					return;
				}
			}
		}
		
		private class RejectEnvConfigAction extends AbstractAction
		{
			public RejectEnvConfigAction(String text, ImageIcon icon){
				super(text, icon);
			}

			@Override
			public void actionPerformed(ActionEvent arg0) {
				String s = ConnectionTester.getConfigFileName();
				if(s != null){
					ConnectionTester.saveEnvironment(".rejected/" + s +".xml");
					ConnectionTester.deleteEnvironment("./submitted/" + s + ".xml");
				} else {
					JOptionPane.showMessageDialog(null, "No file loaded");
					return;
				}
			}
		}
		
		private class NewNodeAction extends AbstractAction{
			public NewNodeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				Node node = new Node();
				ConnectionTester.addNode(node);
				ConnectionTester.setSelected(node);
				((EnvironmentConfigDesignerPanel)getParentContainer()).refreshAttributesPanel();
				System.out.println("Adding New Node in Canvas");
			}
		}
		
		private class NewChannelAction extends AbstractAction{
			public NewChannelAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				CommunicationChannel channel = new CommunicationChannel();
				final JPanel optionPane = new JPanel();
				HashMap<Long, Node> nodes = ConnectionTester.getEnvironmentConfig().getNodes();
				List<String> names = new ArrayList<String>();
				List<Long> keys = new ArrayList<Long>();
				keys.addAll(nodes.keySet());
				for(Long key : keys){
					names.add(nodes.get(key).getComputerName());
					
				}
				String first = (String)JOptionPane.showInputDialog(
	                    null,
	                    "Select initiator node",
	                    "Add Channel",
	                    JOptionPane.PLAIN_MESSAGE,
	                    null,
	                    names.toArray(),
	                    names.get(0).toString());
				if(first != null){
					String second = (String)JOptionPane.showInputDialog(
		                    null,
		                    "Select listener node",
		                    "Add Channel",
		                    JOptionPane.PLAIN_MESSAGE,
		                    null,
		                    names.toArray(),
		                    names.get(0).toString());
					if(second != null){
						channel.setInitiatorNode(keys.get(names.indexOf(first)));
						channel.setListeningNode(keys.get(names.indexOf(second)));
						ConnectionTester.getEnvironmentConfig().addChannel(channel);
						ConnectionTester.setSelected(channel);
						((EnvironmentConfigDesignerPanel)getParentContainer()).refreshAttributesPanel();
						System.out.println("Add New Channel in Canvas");
					}
				}
			}
		}
		
		private class DeleteNodeAction extends AbstractAction{
			public DeleteNodeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				Object selected = ConnectionTester.getEnvironmentConfig().getSelectedObj();
				HashMap<Long, Node> nodes = ConnectionTester.getEnvironmentConfig().getNodes();
				if(selected instanceof Node){
					int option = JOptionPane.showConfirmDialog(null, 
							"Deleting a node will delete any channels connected to it, are you sure?", 
							"Confirm Delete Node", JOptionPane.OK_CANCEL_OPTION);					
					if(JOptionPane.OK_OPTION == option){
						List<CommunicationChannel> toRemoveC = new ArrayList<CommunicationChannel>();
						for(CommunicationChannel channel : ConnectionTester.getEnvironmentConfig().getChannels()){
							if((Node)selected == (nodes.get(channel.getInitiatorNode()))){
								toRemoveC.add(channel);
							} else if ((Node)selected == (nodes.get(channel.getListeningNode()))){
								toRemoveC.add(channel);
							}
						}
						for(CommunicationChannel channel : toRemoveC){
							ConnectionTester.getEnvironmentConfig().removeChannel(channel);
						}
						List<Long> toRemoveN = new ArrayList<Long>();
						for(Long node:nodes.keySet()){
							if(nodes.get(node).equals(selected)){
								toRemoveN.add(node);
							}
						}
						for(Long key : toRemoveN){
							ConnectionTester.getEnvironmentConfig().removeNode(key);
							ConnectionTester.getEnvironmentConfig().setSelectedObj(null);
						}
						System.out.println("Deleting Node in Canvas");
						((EnvironmentConfigDesignerPanel)getParentContainer()).refreshAttributesPanel();
					}
				} else {
					JOptionPane.showMessageDialog(null, "No Node is currently selected");
				}
				System.out.println("Deleting Node in Canvas");
			}
		}
		
		private class DeleteChannelAction extends AbstractAction{
			public DeleteChannelAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				Object selected = ConnectionTester.getEnvironmentConfig().getSelectedObj();
				if(selected instanceof CommunicationChannel){
					ConnectionTester.getEnvironmentConfig().removeChannel((CommunicationChannel)selected);
					ConnectionTester.getEnvironmentConfig().setSelectedObj(null);
					System.out.println("Deleting Channel in Canvas");
					((EnvironmentConfigDesignerPanel)getParentContainer()).refreshAttributesPanel();
				} else {
					JOptionPane.showMessageDialog(null, "No Channel is currently selected");
				}
			}
		}
		
		private class RunSimulationAction extends AbstractAction{
			public RunSimulationAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				if(Toolbar.this.getParent() instanceof SimulationPanel){
					SimulationPanel panel = (SimulationPanel)Toolbar.this.getParent();
					panel.playSelected();
				}
				System.out.println("Running Simulation");
			}
		}
		
		private class StopSimulationAction extends AbstractAction{
			public StopSimulationAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				if(Toolbar.this.getParent() instanceof SimulationPanel){
					SimulationPanel panel = (SimulationPanel)Toolbar.this.getParent();
					panel.stopSelected();
				}
				System.out.println("Stopping Simulation");
			}
		}
		
		private class EditModeAction extends AbstractAction{
			public EditModeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				//create new
				System.out.println("Switching to Edit Mode");
				ConnectionTester.setDesignerMode();
				MainFrame.LaunchEnvConfigDesignerGUI();
			}
		}
		
		private class SecurityModeAction extends AbstractAction{
			public SecurityModeAction(String text, ImageIcon icon){
				super(text, icon);
			}
			public void actionPerformed(ActionEvent e){
				//create new
				System.out.println("Switching to Security Mode");
				ConnectionTester.setSecurityMode();
				MainFrame.LaunchSecurityGUI();
			}
		}
		
		public void paintComponent(Graphics g){
			super.paintComponent(g);
			Object selected = ConnectionTester.getEnvironmentConfig().getSelectedObj();
			if(selected instanceof Node){
				nothing.setVisible(true);
				simulation.setVisible(true);
				software.setVisible(true);
				if(((Node)selected).getNodeState() == NodeState.RUNNING_SIMULATION){
					simulation.setSelected(true);
				} else if (((Node)selected).getNodeState() == NodeState.RUNNING_SOFTWARE){
					software.setSelected(true);
				} else {
					nothing.setSelected(true);
				}
			} else {
				nothing.setVisible(false);
				simulation.setVisible(false);
				software.setVisible(false);
			}
		}
		
}


